using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using System.Net;
using System.IO;
using Frankfort.Threading.Internal;
using System.Threading;


class HttpDownloadManager : Singleton<HttpDownloadManager>
{
	public const int maxRuningCount = 1;
	public const int maxRetryCount = 5;
	private const int requestDownloadSize = 10 * 1024 * 1024; //10MB
	private static string cachePath = CommonUtil.cachePath + "/download_cache";
	private static Semaphore semaphore = new Semaphore(0, 10000);
	private Dictionary<string, HttpDownloadTask> taskMap = new Dictionary<string, HttpDownloadTask>();
	private LinkedList<HttpDownloadRequest> waitQueue = new LinkedList<HttpDownloadRequest>();
	private LinkedList<HttpDownloadRequest> runingQueue = new LinkedList<HttpDownloadRequest>();
	private LinkedList<ThreadInfo> threads = new LinkedList<ThreadInfo>();
	
	public int getRuningCount()
	{
		return runingQueue.Count;
	}
	
	public static void createDir()
	{
		CommonUtil.CreateDir(cachePath);
	}
	
	class ThreadInfo
	{
		bool _cancel = false;
		
		public void cancel()
		{
			_cancel = true;
		}
		
		public void start(HttpDownloadManager manager)
		{
			SingleThreadStarter.StartSingleThread(() =>
			                                      {
				while(!_cancel)
				{
					semaphore.WaitOne();
					if(_cancel)
					{
						break;
					}
					
					HttpDownloadRequest request = null;
					lock(manager)
					{
						if(manager.waitQueue.Count > 0)
						{
							request = manager.waitQueue.Last.Value;
							manager.waitQueue.RemoveLast();
							manager.runingQueue.AddFirst(request);
						}
					}
					
					while(request != null && !request.completed)
					{
						request.Request(false);
						if(!request.canRetry)
						{
							break;
						}
					}
				}
			});
		}
	}
	
	public HttpDownloadManager()
	{
		for(int i = 0; i < maxRuningCount; i++)
		{
			ThreadInfo info = new ThreadInfo();
			threads.AddFirst(info);
			info.start(this);
		}
		
//		DataChangeBroadcast.Instance.Subscribe(DataChangeType.ApplicationQuit, OnApplicationQuit);
	}
	
	public void delTempFiles()
	{
		if(!Directory.Exists(cachePath))
		{
			return;
		}
		
		string[] paths = Directory.GetFiles(cachePath, "*", SearchOption.AllDirectories);
		for(int i = 0; i < paths.Length; i++)
		{
			CommonUtil.Delete(paths[i]);
		}
	}
	
//	private void OnApplicationQuit(DataChangeType type, params object[] objs)
//	{
//		this.CancelAll();
//	}
	
	private HttpDownloadTask getTask(string url)
	{
		HttpDownloadTask request = null;
		if(taskMap.TryGetValue(url, out request))
		{
			return request;
		}
		return null;
	}
	
	public int getRequestProgress(object request)
	{
		if(request == null)
		{
			return 0;
		}
		
		HttpDownloadTask realRequest = (HttpDownloadTask)request;
		return realRequest.getRequestProgress();
	}
	
	public float getRequestSpeed(object request)
	{
		if(request == null)
		{
			return 0;
		}
		
		HttpDownloadTask realRequest = (HttpDownloadTask)request;
		return realRequest.getRequestSpeed();
	}
	
	public int getDownloadTotalConnectCount(object request)
	{
		if(request == null)
		{
			return 0;
		}
		
		HttpDownloadTask realRequest = (HttpDownloadTask)request;
		return realRequest.getDownloadTotalConnectCount();
	}
	
	public int getBadDownloadRetryCount(object request)
	{
		if(request == null)
		{
			return 0;
		}
		
		HttpDownloadTask realRequest = (HttpDownloadTask)request;
		return realRequest.getBadDownloadRetryCount();
	}
	
	public bool isRequestRunning(object request)
	{
		if(request == null)
		{
			return false;
		}
		
		HttpDownloadTask realRequest = (HttpDownloadTask)request;
		return realRequest.isRequestRunning();
	}
	
	public bool isRequestWaiting(object request)
	{
		if(request == null)
		{
			return false;
		}
		
		return !isRequestRunning(request);
	}
	
	public bool isRequestConnecting(object request)
	{
		if(request == null)
		{
			return false;
		}
		
		HttpDownloadTask realRequest = (HttpDownloadTask)request;
		return realRequest.isRequestConnecting();
	}
	
	public bool isRequestReadyConnect(object request)
	{
		if(request == null)
		{
			return false;
		}
		
		HttpDownloadTask realRequest = (HttpDownloadTask)request;
		return realRequest.isRequestReadyConnect();
	}
	
	public object Download(string url, string hash, uint size, uint decompressSize, uint compressType, string path, HttpRedirectHelper redirectHelper, HttpDownloadTask.HttpDownloadHandler handler)
	{
		
		if(url == null)
		{
			return null;
		}
		
		if(!Directory.Exists(cachePath))
		{
			Directory.CreateDirectory(cachePath);
		}
		
		lock(this)
		{
			bool isNew = false;
			HttpDownloadTask task = null;
			if(!taskMap.TryGetValue(url, out task))
			{
				isNew = true;
				//			string fileName = Path.GetFileNameWithoutExtension(url);
				//			fileName = fileName + '_' + CommonUtil.md5(url);
				//			string localPath = cachePath + "/" + fileName;
                task = new HttpDownloadTask(url, hash, path, size, maxRetryCount, redirectHelper, DownloadCallback);
				taskMap.Add(url, task);
			}
			else
			{
				return task;
			}
			
			task.handlersMap[handler] = path;
			
			if(isNew)
			{
				List<HttpDownloadRequest> requests = task.createRequests(requestDownloadSize, decompressSize, maxRuningCount, compressType);
				if(requests != null)
				{
					for(int i = 0; i < requests.Count; i++)
					{
						addRequest(requests[i]);
					}
				}
			}
			
			return task;
		}
	}
	
	//	void autoRunRequest ()
	//	{
	//		while (runingQueue.Count < maxRuningCount && waitQueue.Count > 0)
	//		{
	//			HttpDownloadRequest newRequest = waitQueue.Last.Value;
	//			waitQueue.RemoveLast ();
	//			addRequest (newRequest);
	//		}
	//	}
	
	public void addRequest(HttpDownloadRequest request)
	{
		waitQueue.AddFirst(request);
		semaphore.Release();
	}
	
	public HttpDownloadTask removeTask(string url, bool includeRunning = true)
	{
		HttpDownloadTask task = getTask(url);
		if(task == null)
		{
			return null;
		}

		if(!includeRunning)
		{
			for(int i = 0; i < task.requests.Count; i++)
			{
				if(runingQueue.Contains(task.requests[i]))
				{
					return null;
				}
			}

			task.Cancel();
			taskMap.Remove(url);

			for(int i = 0; i < task.requests.Count; i++)
			{
				waitQueue.Remove(task.requests[i]);
			}
		}
		else
		{
			task.Cancel();
			taskMap.Remove(url);

			for(int i = 0; i < task.requests.Count; i++)
			{
				runingQueue.Remove(task.requests[i]);
				waitQueue.Remove(task.requests[i]);
			}
		}
		
		return task;
	}
	
	public bool Cancel(string url, HttpDownloadTask.HttpDownloadHandler handler)
	{
		if(url == null)
		{
			return true;
		}

		lock(this)
		{
			HttpDownloadTask task = null;
			if(!taskMap.TryGetValue(url, out task))
			{
				return false;
			}
			
			if(!task.handlersMap.Remove(handler))
			{
				return false;
			}
			
			if(task.handlersMap.Count <= 0)
			{
				removeTask(url, false);
			}
		}
		return true;

		//		if(url == null)
		//		{
		//			return true;
		//		}
		//
		//		HttpDownloadTask task = null;
		//		if(!taskMap.TryGetValue(url, out task))
		//		{
		//			return false;
		//		}
		//
		//		if(!task.handlersMap.Remove(handler))
		//		{
		//			return false;
		//		}
		//
		//		if(task.handlersMap.Count <= 0)
		//		{
		//			removeTask(url);
		//		}
		//		return true;
	}
	
	public void CancelAll()
	{
		lock(this)
		{
			Dictionary<string, HttpDownloadTask>.Enumerator enumerator = taskMap.GetEnumerator();
			while(enumerator.MoveNext())
			{
				HttpDownloadTask task = enumerator.Current.Value;
				task.Cancel();
			}
			
			waitQueue.Clear();
			runingQueue.Clear();
			taskMap.Clear();
		}
	}
	
	private void DownloadCallback(HttpDownloadTask task, HttpDownloadRequest request, string url, String localPath, DownloadError status)
	{
		lock(this)
		{
			if(request != null)
			{
				runingQueue.Remove(request);
			}
			else
			{
				removeTask(url);
				if(task == null)
				{
					return;
				}
				
				task.CallBack(status);
			}
		}
	}
}
